﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ERF;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

namespace FirstPerson.Objects.Weapons
{
    public class WeaponHitEventArgs : EventArgs {
        private Player player;
        public WeaponHitEventArgs(Player player) {
            this.player = player;
        }
        public Player Player {
            get { return this.player; }
        }
    }
    /// <summary>
    /// Base class for all weapons.
    /// </summary>
    public abstract class WeaponBase : ModelGameObject
    {
        /// <summary>
        /// Enum providing unique IDs for each weapon in the game.
        /// </summary>
        public enum WeaponId { AK47 };

        protected SoundEffect emptySound;

        public WeaponId weaponId;
        public bool isShooting;
        protected BasicShaderEffect effect;
        protected Player holder;
        private Vector3 positionOffset;
        private int ammunition, maxAmmunition;
        protected Hud hud;
        public event EventHandler<WeaponHitEventArgs> Hit;

        protected SoundHandler sound;

        /// <summary>
        /// Creates a new instance of Weaponbase.
        /// </summary>
        /// <param name="game">The game this instance belongs to.</param>
        /// <param name="holder">The player that is the holder of this weapon.</param>
        /// <param name="weaponModel">The asset name for the weapon model.</param>
        /// <param name="positionOffset">The position offset relative to the player.</param>
        public WeaponBase(ERFGame game, Player holder, string weaponModel, Vector3 positionOffset)
            : base(game)
        {
            this.holder = holder;
            this.positionOffset = positionOffset;
            base.ObjectModel = game.Content.Load<Model>(weaponModel);
            this.hud = (Hud)game.Services.GetService(typeof(Hud));
            this.CreateEffects();
            this.Hit += new EventHandler<WeaponHitEventArgs>(WeaponBase_Hit);
            this.sound = game.SoundHandler;
        }

        private void WeaponBase_Hit(object sender, WeaponHitEventArgs e) {
            e.Player.Hp -= this.Damage;
            NetworkHandler network = (NetworkHandler)base.CurrentGame.Services.GetService(typeof(NetworkHandler));
            //network.Send(NetworkHandler.packetType.Hit, 
        }

        /// <summary>
        /// Raises the Hit event notifying that a player was shot.
        /// </summary>
        /// <param name="p"></param>
        public void HitPlayer(Player p) {
            if(this.Hit != null)
                this.Hit(this, new WeaponHitEventArgs(p));
        }

        /// <summary>
        /// Sets the Effect for each mesh in the weapon model.
        /// </summary>
        private void CreateEffects()
        {
            for (int i = 0; i < this.ObjectModel.Meshes.Count; i++)
            {
                for (int j = 0; j < this.ObjectModel.Meshes[i].MeshParts.Count; j++)
                {
                    if (this.ObjectModel.Meshes[i].MeshParts[j].Effect is BasicEffect)
                    {
                        BasicEffect oldEffect = this.ObjectModel.Meshes[i].MeshParts[j].Effect as BasicEffect;
                        this.effect = new BasicShaderEffect(base.CurrentGame);
                        this.effect.DiffuseColor = oldEffect.DiffuseColor;
                        this.effect.LightDirection = new Vector3(0, 1, 1);
                        this.effect.AmbientColor = Color.White.ToVector3();
                        this.effect.AmbientIntensity = 0.7f;
                        this.effect.DiffuseIntensity = 1f;
                        this.effect.SpecularColor = oldEffect.SpecularColor;
                        this.effect.SpecularIntensity = 1f;
                        this.effect.SpecularPower = 256;
                        this.effect.Texture = oldEffect.Texture;
                        this.effect.EnableTexture = (effect.Texture != null);
                        this.effect.EnableLight = true;
                        this.effect.FogColor = Color.White.ToVector4();
                        this.effect.FogStart = 10.1f;
                        this.effect.FogEnd = 10f;
                        this.effect.FogEnabled = false;
                    }
                    else
                    {
                        BasicShaderEffect oldEffect = this.ObjectModel.Meshes[i].MeshParts[j].Effect as BasicShaderEffect;
                        this.effect = new BasicShaderEffect(base.CurrentGame);
                        this.effect.DiffuseColor = oldEffect.DiffuseColor;
                        this.effect.LightDirection = new Vector3(0, 1, 1);
                        this.effect.AmbientColor = Color.White.ToVector3();
                        this.effect.AmbientIntensity = 0.7f;
                        this.effect.DiffuseIntensity = 1f;
                        this.effect.SpecularColor = oldEffect.SpecularColor;
                        this.effect.SpecularIntensity = 1f;
                        this.effect.SpecularPower = 256;
                        this.effect.Texture = oldEffect.Texture;
                        this.effect.EnableTexture = (effect.Texture != null);
                        this.effect.EnableLight = true;
                        this.effect.FogColor = Color.White.ToVector4();
                        this.effect.FogStart = 10.1f;
                        this.effect.FogEnd = 10f;
                        this.effect.FogEnabled = false;
                    }
                    
                    this.meshEffects[i][j] = effect;
                }
            }
        }

        public override void DrawSolid(GameTime gameTime)
        {

            base.DrawSolid(gameTime);
        }

        /// <summary>
        /// Gets or sets the amount of ammunition in this weapon.
        /// </summary>
        public int Ammunition {
            get { return this.ammunition; }
            set { 
                this.ammunition = value;
            }
        }

        /// <summary>
        /// Gets or sets the max amount of ammunition in this weapon.
        /// </summary>
        public int MaxAmmunition
        {
            get { return this.maxAmmunition; }
            set
            {
                this.maxAmmunition = value;
            }
        }

        /// <summary>
        /// Gets the position offset relative to the player.
        /// </summary>
        public Vector3 PositionOffset
        {
            get { return this.positionOffset; }
        }

        public abstract void Shoot();
        public abstract short Damage {
            get;
        }

        public virtual void BeginShooting() 
        {
            if (!this.isShooting && this.ammunition <= 0)
            {
                this.Play3DSound(emptySound);
            }
            else
            {
                if (this.holder is HumanPlayer)
                {
                    (base.CurrentGame.NetworkHandler as FirstPerson.NetworkHandler).Send(NetworkHandler.packetType.BeginFire, Convert.ToByte(this.weaponId));
                }
            }
            this.isShooting = true;
        }

        public virtual void EndShooting()
        {
            if (this.isShooting && this.holder is HumanPlayer)
            {
                (base.CurrentGame.NetworkHandler as FirstPerson.NetworkHandler).Send(NetworkHandler.packetType.EndFire, Convert.ToByte(this.weaponId));
            }
            this.isShooting = false;
        }

        protected void Play3DSound(SoundEffect soundEffect)
        {

            SoundEffectInstance soundInstance = soundEffect.CreateInstance();
            soundInstance.Volume = 0.7f;
            sound.Play3DSound(soundInstance, this.holder, (base.CurrentGame.PlayerHandler as FirstPerson.PlayerHandler).HumanPlayer);

        }
    }
}
